
use std::{env, fs};
use pest_derive::Parser;
use pest::Parser;

#[derive(Parser)]
#[grammar = "lexer.pest"]
struct SysYLexer;

fn main() {
    // 收集命令行参数
    let args: Vec<String> = env::args().collect();
    // 检查是否提供了文件名
    if args.len() < 2 {
        eprintln!("Usage: {} <filename>", args[0]);
        std::process::exit(1);
    }
    // 获取文件名
    let filename = &args[1];

    // 读取输入文件
    let input = match fs::read_to_string(filename) {
        Ok(content) => content,
        Err(e) => {
            eprintln!("Error: Failed to read file '{}' - {}", filename, e);
            std::process::exit(1);
        }
    };
    
    // 词法分析并打印结果
    tokenize(&input);
}

fn tokenize(input: &str) {
    // 使用 pest 解析输入
    let pairs = match SysYLexer::parse(Rule::main, input) {
        Ok(pairs) => pairs,
        Err(e) => {
            // 解析失败时，打印错误信息
            eprintln!("Error type A: {}", e);
            return; // 存在错误时，不输出 token 信息
        }
    };

    // 遍历匹配到的所有词法单元
    for pair in pairs {
        // `pair.into_inner()` 获取嵌套的规则，也就是我们定义的 `token` 规则
        for inner_pair in pair.into_inner() {
            let (line_no, _) = inner_pair.as_span().start_pos().line_col();
            let text = inner_pair.as_str();

            // 根据匹配到的规则类型，打印相应的 token 信息
            match inner_pair.as_rule() {
                // 关键字
                Rule::CONST => eprintln!("CONST {} at Line {}.", text, line_no),
                Rule::INT => eprintln!("INT {} at Line {}.", text, line_no),
                Rule::VOID => eprintln!("VOID {} at Line {}.", text, line_no),
                Rule::IF => eprintln!("IF {} at Line {}.", text, line_no),
                Rule::ELSE => eprintln!("ELSE {} at Line {}.", text, line_no),
                Rule::WHILE => eprintln!("WHILE {} at Line {}.", text, line_no),
                Rule::BREAK => eprintln!("BREAK {} at Line {}.", text, line_no),
                Rule::CONTINUE => eprintln!("CONTINUE {} at Line {}.", text, line_no),
                Rule::RETURN => eprintln!("RETURN {} at Line {}.", text, line_no),
                // 运算符和分隔符
                Rule::PLUS => eprintln!("PLUS {} at Line {}.", text, line_no),
                Rule::MINUS => eprintln!("MINUS {} at Line {}.", text, line_no),
                Rule::MUL => eprintln!("MUL {} at Line {}.", text, line_no),
                Rule::DIV => eprintln!("DIV {} at Line {}.", text, line_no),
                Rule::MOD => eprintln!("MOD {} at Line {}.", text, line_no),
                Rule::ASSIGN => eprintln!("ASSIGN {} at Line {}.", text, line_no),
                Rule::EQ => eprintln!("EQ {} at Line {}.", text, line_no),
                Rule::NEQ => eprintln!("NEQ {} at Line {}.", text, line_no),
                Rule::LT => eprintln!("LT {} at Line {}.", text, line_no),
                Rule::GT => eprintln!("GT {} at Line {}.", text, line_no),
                Rule::LE => eprintln!("LE {} at Line {}.", text, line_no),
                Rule::GE => eprintln!("GE {} at Line {}.", text, line_no),
                Rule::NOT => eprintln!("NOT {} at Line {}.", text, line_no),
                Rule::AND => eprintln!("AND {} at Line {}.", text, line_no),
                Rule::OR => eprintln!("OR {} at Line {}.", text, line_no),
                Rule::L_PAREN => eprintln!("L_PAREN {} at Line {}.", text, line_no),
                Rule::R_PAREN => eprintln!("R_PAREN {} at Line {}.", text, line_no),
                Rule::L_BRACE => eprintln!("L_BRACE {} at Line {}.", text, line_no),
                Rule::R_BRACE => eprintln!("R_BRACE {} at Line {}.", text, line_no),
                Rule::L_BRACKT => eprintln!("L_BRACKT {} at Line {}.", text, line_no),
                Rule::R_BRACKT => eprintln!("R_BRACKT {} at Line {}.", text, line_no),
                Rule::COMMA => eprintln!("COMMA {} at Line {}.", text, line_no),
                Rule::SEMICOLON => eprintln!("SEMICOLON {} at Line {}.", text, line_no),
                // 标识符
                Rule::IDENT => eprintln!("IDENT {} at Line {}.", text, line_no),
                // 数字常量
                Rule::INTEGER_CONST => {
                    let value = match inner_pair.into_inner().next().unwrap().as_rule() {
                        Rule::HEX_CONST => {
                            // 移除 "0x" 或 "0X" 前缀
                            i64::from_str_radix(&text[2..], 16).unwrap()
                        }
                        Rule::OCTAL_CONST => {
                            // 将八进制字符串转换为十进制
                            i64::from_str_radix(&text, 8).unwrap()
                        }
                        Rule::DECIMAL_CONST => {
                            text.parse::<i64>().unwrap()
                        }
                        _ => unreachable!(),
                    };
                    eprintln!("INTEGER_CONST {} at Line {}.", value, line_no);
                }
                // 忽略主规则和其他辅助规则
                Rule::main | Rule::token | Rule::HEX_CONST | Rule::OCTAL_CONST | Rule::DECIMAL_CONST => {
                    continue;
                }
                _ => {
                    // 如果有未被处理的规则，这通常表明 .pest 文件有误
                    eprintln!("Error type A at Line {}: Unrecognized rule '{:?}'", line_no, inner_pair.as_rule());
                    return;
                }
            }
        }
    }
}